﻿using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using SuperGo.SilverlightLib;

namespace SuperGo.Silverlight {
	public enum StoneStatus {
		Normal,
		NormalUnclickable,
		LastMove,
		Hover,
		Suicide,
		Ko,
		MarkedDead,
		WhitePoint,
		BlackPoint
	}

	public partial class Stone {
		public int X { get; set; }
		public int Y { get; set; }
		private StoneState _stoneState;
		private readonly int _boardSize;
		
		public Stone(int row, int column, int boardSize) {
			InitializeComponent();

			X = column;
			Y = row;
			_stoneState = StoneState.Empty;
			_boardSize = boardSize;
		}

		public void Redraw(GoGame game, StoneState potentialStoneState, StoneStatus stoneStatus) {
			Redraw(game, game.GameState, potentialStoneState, stoneStatus);
		}

		public void Redraw(GoGame game) {
			Redraw(game, StoneStatus.Normal);
		}

		public void Redraw(GoGame goGame, StoneStatus stoneStatus) {
			StoneState actualState = goGame.Board[X, Y].State;
			Redraw(goGame, goGame.GameState, actualState, stoneStatus);
		}

		public void Redraw(GoGame goGame, GameState gameState, StoneState state, StoneStatus stoneStatus) {
			if (gameState == GameState.NegotiatingDeadStones) {
				StoneState actualState = goGame.Board[X, Y].State;

				if (actualState == StoneState.Empty) {
					if (goGame.CurrentBlackPoints == null || goGame.CurrentWhitePoints == null)
						goGame.CalculateScore();
					if (goGame.CurrentBlackPoints[X, Y])
						stoneStatus = StoneStatus.BlackPoint;
					if (goGame.CurrentWhitePoints[X, Y])
						stoneStatus = StoneStatus.WhitePoint;
				} else {
					bool markedAsDead = goGame.CurrentDeadStones[X, Y];
					stoneStatus = markedAsDead ? StoneStatus.MarkedDead : stoneStatus;
				}
				SetState(actualState, stoneStatus);
			} else {
				if (goGame.LastMove != null)
					if (goGame.LastMove.X == X && goGame.LastMove.Y == Y)
						stoneStatus = StoneStatus.LastMove;
				SetState(state, stoneStatus);
			}
		}

		public void SetState(StoneState state, StoneStatus status) {
			if (state == StoneState.Empty) {
				ResetStoneState();
				SetVisibility(false);
			} else {
				SetVisibility(true);
				_ellipse.Fill = GetBrush(state);
			}

			_stoneState = state;
			
			SetStatus(status);
		}

		private void SetStatus(StoneStatus status) {
			ResetStoneState();

			switch (status) {
				case StoneStatus.Hover:
					SetStoneOpaque();
					LayoutRoot.Cursor = Cursors.Hand;
					break;
				case StoneStatus.LastMove:
					_ellipse.Stroke = new SolidColorBrush(Colors.Cyan);
					_ellipse.StrokeThickness = 2;
					break;
				case StoneStatus.Ko:
					SetStoneOpaque();
					_textBlock.Visibility = Visibility.Visible;
					_textBlock.Text = "KO";
					SetFontSize(20, 15, 11);
					break;
				case StoneStatus.Suicide:
					SetStoneOpaque();
					_textBlock.Visibility = Visibility.Visible;
					_textBlock.Text = "X";
					SetFontSize(25, 20, 15);
					break;
				case StoneStatus.MarkedDead:
					SetStoneOpaque();
					_textBlock.Visibility = Visibility.Visible;
					_textBlock.Text = "X";
					SetFontSize(25, 20, 15);
					break;
				case StoneStatus.BlackPoint:
					ShowX(Colors.Black);
					break;
				case StoneStatus.WhitePoint:
					ShowX(Colors.White);
					break;
			}
		}

		private void ShowX(Color color) {
			_lineBackSlash.Visibility = Visibility.Visible;
			_lineForwardSlash.Visibility = Visibility.Visible;



			double xLeft = _ellipse.ActualWidth * .25;
			double xRight = _ellipse.ActualWidth * .75;

			double yTop = _ellipse.ActualHeight * .25;
			double yBottom = _ellipse.ActualHeight * .75;

			_lineForwardSlash.X1 = xLeft;
			_lineForwardSlash.Y1 = yTop;
			_lineForwardSlash.X2 = xRight;
			_lineForwardSlash.Y2 = yBottom;

			_lineBackSlash.X1 = xRight;
			_lineBackSlash.Y1 = yTop;
			_lineBackSlash.X2 = xLeft;
			_lineBackSlash.Y2 = yBottom;

			_lineForwardSlash.Stroke = new SolidColorBrush(color);
			_lineBackSlash.Stroke = new SolidColorBrush(color);
		}

		private void ResetStoneState() {
			// clear transparency (it may get reset)
			_shadow.Opacity = 1;
			_ellipse.Opacity = 1;
			// clear the stroke (it may get reset)
			_ellipse.Stroke = null;
			_textBlock.Visibility = Visibility.Collapsed;
			LayoutRoot.Cursor = Cursors.Arrow;
			_lineBackSlash.Visibility = Visibility.Collapsed;
			_lineForwardSlash.Visibility = Visibility.Collapsed;
		}

		private void SetFontSize(double boardSize9, double boardSize13, double boardSize19) {
			double fontSize = boardSize9;

			if (_boardSize == 19)
				fontSize = boardSize19;
			if (_boardSize == 13)
				fontSize = boardSize13;

			_textBlock.FontSize = fontSize;
		}

		private void SetStoneOpaque() {
			double opacity = _stoneState == StoneState.Black ? .3 : .6;
			_shadow.Opacity = opacity;
			_ellipse.Opacity = opacity;
		}

		private void SetVisibility(bool visible) {
			_shadow.Visibility = IsVisible(visible);
			_ellipse.Visibility = IsVisible(visible);
			_textBlock.Visibility = IsVisible(visible);
		}

		private static Visibility IsVisible(bool visible) {
			return visible ? Visibility.Visible : Visibility.Collapsed;
		}

		public Brush GetBrush(StoneState state) {
			if (state == StoneState.Black) {
				RadialGradientBrush radialGradientBrush = new RadialGradientBrush{
					GradientOrigin = new Point(.2, .2)
				};

				radialGradientBrush.GradientStops.Add(new GradientStop {
					Color = Color.FromArgb(255, 80, 80, 80),
					Offset = .2
				});

				radialGradientBrush.GradientStops.Add(new GradientStop {
					Color = Color.FromArgb(255, 10, 10, 10),
					Offset = 1
				});

				return radialGradientBrush;
			}

			if (state == StoneState.White) {
				RadialGradientBrush radialGradientBrush = new RadialGradientBrush{
					GradientOrigin = new Point(.2, .2)
				};

				radialGradientBrush.GradientStops.Add(new GradientStop {
					Color = Colors.White,
					Offset = .2
				});

				radialGradientBrush.GradientStops.Add(new GradientStop {
					Color = Color.FromArgb(255, 200, 200, 200),
					Offset = 1
				});

				return radialGradientBrush;
			}

			throw new Exception("Unknown stone state");
				
		}
	}
}
